/**
  ******************************************************************************
  * @file    timer_software.c
  * @author  ashuai0110
  * @version V2.4
  * @date    2024-09-10
  * @brief   软件定时器
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2023-09-26    ashuai0110    完成基本内容
  * 2023-12-29    ashuai0110    修改从组件计时节拍接口获取时基
  * 2024-01-01    ashuai0110    修改链表挂起逻辑
  * 2024-09-01    ashuai0110    修改超时判断逻辑,删除一些assert
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "timer_software.h"

/**
 * @addtogroup modules
 * @{
 */

/**
 * @defgroup timer_software timer_software
 * @{
 */

/* 私有宏定义-----------------------------------------------------------------*/
/**
 * @defgroup timer_software_local_macros timer software local macros
 * @{
 */

/**
 * @defgroup timer_software_check_parameters_validity timer software check parameters validity
 * @{
 */
/* 软件定时器运行标志有效性检查 */
#define IS_VALID_TIMER_RUN(x)                                                  \
(       ((x) == TIMER_RUN_START)          ||                                   \
        ((x) == TIMER_RUN_STOP))
/**
 * @}
 */

/**
 * @}
 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/
/**
 * @defgroup timer_software_local_variables timer software local variables
 * @{
 */

static timer_s_t *pTimerTaskHead = NULL; /*!< 软件定时器工作链表头节点 */

/**
 * @}
 */

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/

/**
 * @defgroup timer_software_global_functions timer software global functions
 * @{
 */

/**
  * @brief  软件定时器任务初始化
  *
  * @note   创建后的任务默认加入到工作链表中(如需挂起请使用timer_s_pending)
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @param  targetTicks     : 定时时间ms
  *
  * @param  callbackFn      : 回调函数
  *
  * @param  runFlg          : 运行标志 @ref timer_run_flg
  *   @arg  TIMER_RUN_STOP  : 不运行
  *   @arg  TIMER_RUN_START : 运行
  *
  * @retval 返回初始化结果
  *    @arg MW_RET_OK       : 成功
  *    @arg MW_RET_ERR      : 已存在(已被插入)
  */
uint8_t timer_s_init(timer_s_t *_ts, uint32_t targetTicks, mw_normal_fn_t callbackFn, uint8_t runFlg)
{
    MW_ASSERT_PARAM(IS_VALID_POINTER(_ts));
    MW_ASSERT_PARAM(IS_VALID_POINTER(callbackFn));
    MW_ASSERT_PARAM(IS_VALID_TIMER_RUN(runFlg));
    
    /* 初始化各参数 */
    memset(_ts, 0, sizeof(timer_s_t));
    _ts->curTicks = mw_tick_get();
    _ts->targetTicks = targetTicks;
    _ts->callbackFn = callbackFn;
    _ts->runFlg = runFlg;
    /* 初始化时就插入链表 */
    return timer_s_insert(_ts);
}

/**
  * @brief  软件定时器任务取消初始化
  *
  * @param  _ts : 软件定时器任务实例
  *
  * @retval None
  */
void timer_s_de_init(timer_s_t *_ts)
{
    /* 取消初始化时从链表取下并将参数全部置零 */
    timer_s_pending(_ts);
    memset(_ts, 0, sizeof(timer_s_t));
}

/**
  * @brief  软件定时器任务插入(插入工作链表)
  *
  * @param  _ts     : 软件定时器任务实例
  *
  * @retval 返回结果
  *    @arg MW_RET_OK  : 成功
  *    @arg MW_RET_ERR : 已存在(已被插入)
  */
uint8_t timer_s_insert(timer_s_t *_ts)
{
    timer_s_t *tsTarget;
    
    tsTarget = pTimerTaskHead; /* 拿到链表头节点 */
    /* 遍历查重 重复则返回错误 */
    while(NULL != tsTarget)
    {
        if(tsTarget == _ts) { return MW_RET_ERR; }
        tsTarget = tsTarget->pNext;
    }
    /* 否则使用头插法(后来居上)将此节点插入链表 */
    _ts->pNext = pTimerTaskHead;
    pTimerTaskHead = _ts;
    
    return MW_RET_OK;
}

/**
  * @brief  软件定时器任务挂起(从工作链表中取下)
  *
  * @param  _ts     : 软件定时器任务实例
  *
  * @retval 返回结果
  *    @arg MW_RET_OK  : 成功
  *    @arg MW_RET_ERR : 不存在(已被挂起)
  */
uint8_t timer_s_pending(timer_s_t *_ts)
{
    timer_s_t **tsTarget;
    
    tsTarget = &pTimerTaskHead; /* 先拿到头节点的地址 */
    /* 遍历寻找此节点 */
    while(*tsTarget != _ts)
    {
        if(NULL == *tsTarget) { return MW_RET_ERR; }
        tsTarget = &(*tsTarget)->pNext;
    }
    *tsTarget = _ts->pNext; /* 将此节点指针改为下一节点指针 即移除此节点 */

    return MW_RET_OK;
}

/**
  * @brief  软件定时器任务轮询处理
  *
  * @param  None
  *
  * @retval None
  */
void timer_s_poll(void)
{
    timer_s_t *tsTarget;
    
    /* 遍历链表 */
    for(tsTarget = pTimerTaskHead; tsTarget; tsTarget = tsTarget->pNext)
    {
        /* 运行标志为开启运行才执行 */
        if(TIMER_RUN_START == tsTarget->runFlg)
        {
            if((mw_tick_get() - tsTarget->curTicks) > tsTarget->targetTicks)
            {
                /* 当前计数值达到目标计数值则执行回调函数并记录最新组件计时节拍 */
                tsTarget->callbackFn();
                tsTarget->curTicks = mw_tick_get();
            }
        }
    }
}

/**
  * @brief  设置软件定时器任务的目标计数值ms
  *
  * @param  _ts         : 软件定时器任务实例
  *
  * @param  targetTicks : 目标计数值ms
  *
  * @retval None
  */
void timer_s_set_target_ticks(timer_s_t *_ts, uint32_t targetTicks)
{
    _ts->targetTicks = targetTicks;
}

/**
  * @brief  获取软件定时器任务的目标计数值ms
  *
  * @param  _ts : 软件定时器任务实例
  *
  * @retval 返回目标计数值ms
  */
uint32_t timer_s_get_target_ticks(timer_s_t *_ts)
{
    return _ts->targetTicks;
}

/**
  * @brief  设置软件定时器任务的运行标志
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @param  runFlg          : 运行标志 @ref timer_run_flg
  *   @arg  TIMER_RUN_STOP  : 不运行
  *   @arg  TIMER_RUN_START : 运行
  *
  * @retval None
  */
void timer_s_set_run(timer_s_t *_ts, uint8_t runFlg)
{
    MW_ASSERT_PARAM(IS_VALID_TIMER_RUN(runFlg));
    
    _ts->runFlg = runFlg;
    _ts->curTicks = mw_tick_get();
}

/**
  * @brief  获取软件定时器任务的运行标志
  *
  * @param  _ts             : 软件定时器任务实例
  *
  * @retval 返回运行标志 @ref timer_run_flg
  *    @arg TIMER_RUN_STOP  : 不运行
  *    @arg TIMER_RUN_START : 运行
  */
uint8_t timer_s_get_run(timer_s_t *_ts)
{
    return _ts->runFlg;
}

/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
